#include "offParser.h"

using namespace std;

bool MeshUtils::OffParser::parseNode(std::ifstream& source, double& x, double& y, double& z)
{
	Lexeme lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER and lex.type != REAL)
		throw ParserException("Failed to read x coord");
	if(lex.type == INTEGER)
		x = (double) lex.integer;
	else
		x = (double) lex.real;
	
	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER and lex.type != REAL)
		throw ParserException("Failed to read y coord");
	if(lex.type == INTEGER)
		y = (double) lex.integer;
	else
		y = lex.real;
	
	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER and lex.type != REAL)
		throw ParserException("Failed to read z coord");
	if(lex.type == INTEGER)
		z = (double) lex.integer;
	else
		z = (double) lex.real;

	lex = ParserHelper::lexer(source);
	if(lex.type != EOL)
		throw ParserException("Failed to read eol");

	return true;
}

bool MeshUtils::OffParser::parseFace(std::ifstream& source, unsigned int& A, unsigned int& B, unsigned int& C)
{
	Lexeme lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER)
		throw ParserException("Failed to read face nodes number");
	if(lex.integer != 3)
		throw ParserException("Face does not have 3 nodes");

	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER)
		throw ParserException("Failed to read face : invalid number of nodes in nodesList");
	A = lex.integer;
	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER)
		throw ParserException("Failed to read face : invalid number of nodes in nodesList");
	B = lex.integer;
	lex = ParserHelper::lexer(source);
	if(lex.type != INTEGER)
		throw ParserException("Failed to read face : invalid number of nodes in nodesList");
	C = lex.integer;

	lex = ParserHelper::lexer(source);
	if(lex.type != EOL)
		throw ParserException("Failed to eol");

	return true;
}

void MeshUtils::OffParser::load(std::vector<MeshUtils::Vector3>& nodes, std::vector<MeshUtils::Face_t>& faces,  unsigned int& nbNodes, unsigned int& nbFaces)
{
	std::ifstream infile(filename);

	try {
		Lexeme lex = ParserHelper::lexer(infile);

		if(lex.type != ALPHA or (string(lex.alpha).compare("OFF") != 0))//OFF "header"
			throw ParserException("Bad OFF format : fist line should be OFF");
		
		lex = ParserHelper::lexer(infile);
		if(lex.type != EOL)
			throw ParserException("Failed to eol");

		lex = ParserHelper::lexer(infile); //nodes number
		cout << lex.type << endl;
		if(lex.type != INTEGER)
			throw ParserException("Bad OFF format : failed to read nodes number");
		nbNodes = lex.integer;
		
		lex = ParserHelper::lexer(infile); //faces number
		if(lex.type != INTEGER)
			throw ParserException("Bad OFF format : failed to read faces number");
		nbFaces = lex.integer;

		lex = ParserHelper::lexer(infile); //edge number -> useless
		if(lex.type != INTEGER)
			throw ParserException("Bad OFF format : failed to read faces number");

		lex = ParserHelper::lexer(infile);
		if(lex.type != EOL)
			throw ParserException("Failed to eol");

		//Parse nodes
		MeshUtils::Vector3 node;
		for(unsigned int i = 0 ; i < nbNodes ; i++)
		{
			parseNode(infile, node.x, node.y, node.z);
			MeshUtils::Vector3 nodeCopy = node;
			nodes.push_back(nodeCopy);
		}

		//Parse elts
		for(unsigned int i = 0 ; i < nbFaces ; i++)
		{
			MeshUtils::Face_t face;
			parseFace(infile, face.A, face.B, face.C );
			faces.push_back(face);
		}
		std::cout << "end parsing faces : " << nbFaces << " faces (counted) " << endl;
	
	} catch(ParserException e)
	{
		infile.close();
		std::cout << e.what() << std::endl;
		exit(0);
	}
	
	infile.close();
	return;
}
